package com.grape.api.v1;

import com.grape.annotation.OperateMethodName;
import com.grape.enums.VerifyCodeEnum;
import com.grape.error.BusinessException;
import com.grape.redis.service.IRedisService;
import com.grape.result.R;
import com.grape.utils.SendCodeUtils;
import com.grape.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.security.Principal;
import java.util.Date;
import java.util.Map;

import static com.grape.result.R.argumentError;
import static com.grape.result.R.operationSuccess;

@RestController
@AllArgsConstructor
public class AuthController {

    private final TokenEndpoint tokenEndpoint;

    private final CheckTokenEndpoint checkTokenEndpoint;

    private final TokenStore tokenStore;

    private final IRedisService redisService;

    private final SendCodeUtils sendCodeUtils;

    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);

    @GetMapping("/oauth/token")
    public R getToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return this.postToken(principal, parameters);
    }

    @PostMapping("/oauth/token")
    public R postToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        if (StringUtils.isNotBlank(parameters.get("key"))) {
            parameters.put("client_id", "qrcode_client_id");
            parameters.put("client_secret", "123");
            return tokenByQrcode(principal, parameters);
        }
        if (!parameters.containsKey("grant_type")) {
            throw new BusinessException("请求参数中必须包含grant_type");
        }
        if (!parameters.containsKey("client_id")) {
            throw new BusinessException("请求参数中必须包含client_id");
        }
        if (!parameters.containsKey("client_secret")) {
            throw new BusinessException("请求参数中必须包含client_secret");
        }
        OAuth2AccessToken auth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
        return R.resultSuccess(auth2AccessToken, null);
    }

    public R tokenByQrcode(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        OAuth2AccessToken auth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
        /**
         * 流程
         * 1、前端发送请求到后台，后台生成一个uuid，并将uuid生成二维码，然后返回给pc，发送延迟消息给mq，1分钟后检查qrcode的状态是否为扫了，反之过期
         * 2、pc上显示二维码，然后用户使用记账app扫码，跳转到授权页面，并识别二维码是 key，根据key和自身的 Authorization 取出用户id发送请求到oauth/token，（目前想到的方式）
         * 3、服务器收到请求后处理请求，正常走完授权流程后（已经处理判断二维码是否已经过期），然后判断是否为二维码登录，是的话取出key然后发送消息给pc端（包含token）
         * 4、pc端接收到token后提示用户扫码登录成功，然后跳转到系统首页
         */
        // 判断类型，如果是qrcode的话再根据key发送消息给前端，登录成功
        String key = parameters.get("key");
        // 根据uuid拼接成key然后将value的时间设置为0，或者删除，这样就能保证mq处理消息时不会发送消息给pc
        redisService.deleteKey(VerifyCodeEnum.QR_CODE_TIME_OUT.join(key));
        // TODO
//        websocketFeign.sendMessage(WebsocketResult.loginSuccess(auth2AccessToken, key));
        return R.resultSuccess(null, null);
    }

    @GetMapping("/oauth/check_token")
    public R postToken(@RequestParam String token) throws HttpRequestMethodNotSupportedException {
        Map<String, ?> stringMap = checkTokenEndpoint.checkToken(token);
        return R.resultSuccess(stringMap, null);
    }

    @GetMapping("/oauth/createToken")
    public R createToken(@RequestParam String clientId, Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        //ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
        //TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
        //OAuth2AccessToken accessToken = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
        OAuth2AccessToken accessToken = null;
        return R.resultSuccess(accessToken, null);
    }

    @PostMapping("/oauth/logout")
    public R logout(HttpServletRequest request){
        String authorization = request.getHeader("Authorization").replace("bearer ", "");
        Jwt jwt= JwtHelper.decode(authorization);
        String claims=jwt.getClaims();
//        JwtUser jwtUser = JSON.parseObject(claims, JwtUser.class);
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(authorization);
        logger.error("oAuth2AccessToken.getExpiration().getTime() = " + oAuth2AccessToken.getExpiresIn());
//        LoginVal loginVal = OauthUtils.getCurrentUser();
        // 这个jti放入redis中，并且过期时间设置为token的过期时间
//        redisService.setAndTime(OAuthConstant.JTI_KEY_PREFIX + jwtUser.getJti(),"", (long) oAuth2AccessToken.getExpiresIn());
        return R.logoutSuccess(null, null);
    }

    @PostMapping("/oauth/sendCode")
    @ApiOperation(value = "发送验证码", notes = "发送验证码")
    @OperateMethodName(value = "发送验证码", url = "oauth:auth:sendCode")
    public R sendCode(@NotBlank(message = "手机号码不能为空") @RequestParam String phone){
        StringBuilder codeSB = new StringBuilder();
        sendCodeUtils.sendCode(phone, codeSB);
        return operationSuccess(codeSB.toString(), null);
    }

}
